package com.loong.common.utils;

import com.loong.common.function.CommonConsumer;
import com.loong.common.function.CommonExecutor;
import com.loong.common.function.CommonFunction;
import com.loong.common.function.CommonParamsFunction;
import org.jetbrains.annotations.NotNull;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class TreeUtils {
    public static  <T> List<T> toTree(List<T> sources, CommonFunction<T,Boolean> isTop, CommonParamsFunction<T,Boolean> isParent, CommonConsumer setChildren, Function<T,Comparable> sorted, CommonExecutor empty){
        if(CollectionUtils.isEmpty(sources))return sources;
        Stream<T> tStream = filter(item->isTop.apply((T)item),sources, setChildren, isParent, sorted, empty);
        if(!ObjectUtils.isEmpty(sorted)){
            tStream.sorted(Comparator.comparing(sorted));
        }
        return tStream.collect(Collectors.toList());
    }

    public static  <T> List<T> getChildren(T root, List<T> sources, CommonConsumer setChildren, CommonParamsFunction<T,Boolean> isParent, Function<T,Comparable> sorted, CommonExecutor empty) {
        if(CollectionUtils.isEmpty(sources))return new ArrayList<>();
        Stream<T> tStream = filter(item->isParent.get(root,item),sources, setChildren, isParent, sorted, empty);
        List<T> collect = tStream.collect(Collectors.toList());
        // 表示没子节点了
        if(CollectionUtils.isEmpty(collect)){
            // 结束递归
            if(!ObjectUtils.isEmpty(empty)){
                empty.execute();
            }
            return new ArrayList<>();
        }
        return collect;
    }

    @NotNull
    private static  <T> Stream<T> filter(Predicate<? super T> filter, List<T> sources, CommonConsumer setChildren, CommonParamsFunction<T,Boolean> isParent, Function<T, Comparable> sorted, CommonExecutor empty) {
        Stream<T> tStream = sources
                .stream()
                .filter(filter)
                .map(item -> {
                    setChildren.apply(getChildren(item, sources,setChildren,isParent,sorted,empty));
                    return item;
                });
        if(!ObjectUtils.isEmpty(sorted)){
            tStream.sorted(Comparator.comparing(sorted));
        }
        return tStream;
    }

}
